package com.example.martian.utils;

import com.alibaba.fastjson.JSONObject;
import com.example.martian.config.util.RedisUtils;
import com.example.martian.huobi.exception.SDKException;
import com.example.martian.huobi.utils.ConnectionFactory;
import com.example.martian.mapper.AuthenticationMapper;
import com.example.martian.mapper.CustodyMapper;
import com.example.martian.mapper.MartianOrePoolMapper;
import com.example.martian.mapper.RedPacketMapper;
import com.example.martian.pojo.YzcmObtain;
import com.example.martian.pojo.YzcmRedpacket;
import com.example.martian.pojo.YzcmUser;
import com.example.martian.pojo.YzcmWallet;
import com.example.martian.service.MartianOrePoolService;
import jnr.ffi.annotations.In;
import okhttp3.ConnectionPool;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;


@Component
public class ExchangeRateUtils {

    @Autowired
    private CustodyMapper custodyMapper;

    @Autowired
    private RedPacketMapper redPacketMapper;

    @Autowired
    private AuthenticationMapper authenticationMapper;

    @Autowired
    private MartianOrePoolMapper martianOrePoolMapper;

    @Autowired
    private RedisUtils redisUtils;


    private static final String httpKey = "0d9d342a93446f794927f8100d164632";

    private static final Logger log = LoggerFactory.getLogger(ExchangeRateUtils.class);
    private static Boolean LATENCY_DEBUG_SWATCH = Boolean.FALSE;
    private static LinkedBlockingQueue<ConnectionFactory.NetworkLatency> LATENCY_DEBUG_QUEUE = new LinkedBlockingQueue<>();

    private static ConnectionPool connectionPool =
            new ConnectionPool(20, 300, TimeUnit.SECONDS);

    private static final OkHttpClient client = new OkHttpClient.Builder()
            .followSslRedirects(false)
            .followRedirects(false)
            .connectTimeout(5000, TimeUnit.MILLISECONDS)
            .readTimeout(5000, TimeUnit.MILLISECONDS)
            .writeTimeout(5000, TimeUnit.MILLISECONDS)
            .connectionPool(connectionPool)
            .addNetworkInterceptor(new Interceptor() {
                @NotNull
                @Override
                public okhttp3.Response intercept(@NotNull Chain chain) throws IOException {
                    okhttp3.Request request = chain.request();

                    Long startNano = System.nanoTime();

                    okhttp3.Response response = chain.proceed(request);

                    Long endNano = System.nanoTime();

                    if (LATENCY_DEBUG_SWATCH) {
                        LATENCY_DEBUG_QUEUE.add(new ConnectionFactory.NetworkLatency(request.url().url().getPath(), startNano, endNano));
                    }

                    return response;
                }
            })
            .build();

    public JSONObject exchangeRate(String URL) throws IOException {

        Request request = new Request.Builder()
                .url(URL)
                .get()
                .build();

        String response = ExchangeRateUtils.execute(request);
        return JSONObject.parseObject(response);
    }


    public static String execute(Request request) {

        okhttp3.Response response = null;
        String str = null;
        try {
            log.debug("[Request URL]{}", request.url());
            response = client.newCall(request).execute();
            if (response.code() != 200) {
                throw new SDKException(SDKException.EXEC_ERROR, "[Execute] Response Status Error : " + response.code() + " message:" + response.message());
            }
            if (response != null && response.body() != null) {
                str = response.body().string();
                response.close();
            } else {
                throw new SDKException(SDKException.ENV_ERROR, "[Execute] Cannot get the response from server");
            }
            log.debug("[Response]{}", str);
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            throw new SDKException(SDKException.RUNTIME_ERROR, "[Execute] Cannot get the response from server");
        }
    }

    //币种对换USD汇率
    public String exchange(String coins){
        if (coins.equals("USDT")){
            return "1";
        }
        String coin = coins + "USDT";
        String rateByCoins = redPacketMapper.selectExchangeRateByCoins(coin);
        return rateByCoins;
    }

    public void insertRedPacket(String coin, String sendMoney,String addressUid,Integer number,Integer remainNumber,
                                String address,Integer type,Integer zt,String cipher){
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
        String sj = dateFormat.format(date);
        YzcmRedpacket yzcmRedpacket = new YzcmRedpacket();
        yzcmRedpacket.setCmcCoin(coin);
        yzcmRedpacket.setCmcAddress(address);
        yzcmRedpacket.setCmcType(type);
        yzcmRedpacket.setCmcSj(sj);
        yzcmRedpacket.setCmcMoney(sendMoney);
        yzcmRedpacket.setCmcNumber(number);
        yzcmRedpacket.setCmcRemainNumber(remainNumber);
        yzcmRedpacket.setCmcAddressUid(addressUid);
        yzcmRedpacket.setCmcZt(zt);
        yzcmRedpacket.setCmcCipher(cipher);
        redPacketMapper.insertRedPacket(yzcmRedpacket);
    }

    public void insertRedPacketRoll(String coin, BigDecimal coinMoney, String addressUid,
                                    Integer number, Integer remainNumber, String cmcAddress) {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
        YzcmObtain yzcmObtain = new YzcmObtain();
        yzcmObtain.setCmcAddress(cmcAddress);
        yzcmObtain.setCmcAddressUid(addressUid);
        yzcmObtain.setCmcCoinMoney(coinMoney);
        yzcmObtain.setCmcCoin(coin);
        yzcmObtain.setCmcSj(dateFormat.format(date));
        yzcmObtain.setCmcNumber(number);
        yzcmObtain.setCmcRemainNumber(remainNumber);
        redPacketMapper.insertRedPacketRoll(yzcmObtain);
    }

    public void Authentication(Integer userId,String username,String idNumber,Integer rzZt,String phone){
        YzcmUser yzcmUser = new YzcmUser();
        yzcmUser.setCmcAccountId(userId);
        yzcmUser.setCmcUsername(username);
        yzcmUser.setCmcIdNo(idNumber);
        yzcmUser.setCmcRzZt(rzZt);
        yzcmUser.setCmcPhone(phone);
        authenticationMapper.insertAuthentication(yzcmUser);
    }

    public void custodyWellat(String address,Integer midAddressId,String addressKey,String coinMoney,String coin){
        YzcmWallet yzcmWallet = new YzcmWallet();
        yzcmWallet.setCmcAddress(address);
        yzcmWallet.setCmcCoin(coin);
        yzcmWallet.setCmcMoney(coinMoney);
        yzcmWallet.setCmcAddressKey(addressKey);
        yzcmWallet.setCmcMidAddressId(midAddressId);
        custodyMapper.insertWallet(yzcmWallet);
    }

    public void updateAward(BigDecimal money, Integer addressId, Integer number, Integer type,String address){
        List<Map<String,Object>> list = new ArrayList<>();
        //根据id查询直接邀请和间接邀请id
        List<Map<String, Object>> mapList = martianOrePoolMapper.selectDirectAndIndirectById(addressId);
        for (Map<String, Object> map : mapList){
            if (map == null){
                break;
            }else {
                Integer directId= Integer.parseInt(map.get("cmc_direct_id").toString());//直接邀请ID
                String directRewardRate = martianOrePoolMapper.selectDirectReward(directId);//直接邀请奖励百分比
                BigDecimal directReward = new BigDecimal(directRewardRate).multiply(money).multiply(new BigDecimal(number));//直接邀请人的奖励
                //根据id查询邀请奖励
                String directInviteAward = martianOrePoolMapper.selectInviteAward(directId);//查询直接邀请人的奖励
                //计算总奖励
                BigDecimal addDirectReward = directReward.add(new BigDecimal(directInviteAward));
                if (type == 1){
                    List<Map<String, Object>> mapList1 = martianOrePoolMapper.selectUsdtMoneyById(directId);//直接邀请人的USDT余额
                    for (Map<String, Object> map1 : mapList1){
                        String directAddress = map1.get("cmc_address").toString();
                        String cmcMoney = map1.get("cmc_money").toString();
                        //直接奖励+余额
                        String directDecimal = new BigDecimal(cmcMoney).add(directReward).toPlainString();
                        martianOrePoolMapper.updateUsdtBalance(directDecimal,directAddress);
                    }
                    martianOrePoolMapper.updateAwardById(addDirectReward,directId);
                }
                if (type == 2){
                    List<Map<String, Object>> mapList1 = martianOrePoolMapper.selectUsdtMoneyById(directId);//直接邀请人的USDT余额
                    for (Map<String, Object> map1 : mapList1){
                        Map<String,Object> objectMap = new HashMap<>();
                        String directAddress = map1.get("cmc_address").toString();
                        objectMap.put("address",directAddress);
                        objectMap.put("reward",directReward);
                        list.add(objectMap);
                    }
                }
            }
            if (map.get("cmc_indirect_id") == null){
                break;
            }else {
                Integer indirectId = Integer.parseInt(map.get("cmc_indirect_id").toString());//间接邀请ID
                String indirectRewardRate = martianOrePoolMapper.selectIndirectReward(indirectId);//间接邀请奖励百分比
                //计算单次购买奖励
                BigDecimal indirectReward = new BigDecimal(indirectRewardRate).multiply(money).multiply(new BigDecimal(number));//间接邀请人的奖励
                String indirectInviteAward = martianOrePoolMapper.selectInviteAward(indirectId);//查询间接邀请人的奖励
                BigDecimal addIndirectReward = indirectReward.add(new BigDecimal(indirectInviteAward));
                if (type == 1) {
                    List<Map<String, Object>> mapList2 = martianOrePoolMapper.selectUsdtMoneyById(indirectId);//间接邀请人的USDT余额
                    for (Map<String, Object> map1 : mapList2) {
                        String indirecAddress = map1.get("cmc_address").toString();
                        String cmcMoney = map1.get("cmc_money").toString();
                        //直接奖励+余额
                        String indirectDecimal = new BigDecimal(cmcMoney).add(indirectReward).toPlainString();
                        martianOrePoolMapper.updateUsdtBalance(indirectDecimal, indirecAddress);
                    }
                    //更新邀请奖励
                    martianOrePoolMapper.updateAwardById(addIndirectReward, indirectId);
                }
                if (type == 2) {
                    List<Map<String, Object>> mapList2 = martianOrePoolMapper.selectUsdtMoneyById(indirectId);//间接邀请人的USDT余额
                    for (Map<String, Object> map1 : mapList2) {
                        Map<String,Object> objectMap = new HashMap<>();
                        String indirecAddress = map1.get("cmc_address").toString();
                        objectMap.put("address",indirecAddress);
                        objectMap.put("reward", indirectReward);
                        list.add(objectMap);
                    }
                }
            }
            redisUtils.setCacheListInMap(address+"Reward",list);
        }
    }

}
